package com.watermark.util;

import javax.imageio.*;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.UUID;

/**
 * 向图片写水印 工具类*
 * @author tianyf
 */
public class WriteImageWatermarkUtil {

    /**
     * 设定画笔的 距离 总宽 / 2 是 宽度居中*
     */
    private static Integer widthRatio = 2;
    /**
     * 核定画笔的 距离 总长 / 2 是 长度居中*
     */
    private static Integer heightRatio = 2;
    /**
     * 画笔角度 45度 可调*
     */
    private static Integer angle = 45;
    /**
     * 字体 类型*
     */
    private static String font = "微软雅黑";
    /**
     * 字体大小*
     */
    private static Integer size = 20;
    /**
     * 透明度*
     */
    private static Float transparency = 0.5F;
    /**
     * 水印水平距离*
     */
    private static Integer levelDistance = 20;
    /**
     * 水印垂直距离*
     */
    private static Integer verticalDistance = 20;
    /**
     * 文件后缀*
     */
    private static String suffix = ".jpg";

    /**
     * 向图片写水印,并返回一个全新的图片*
     * @param imgBytes
     * @param text
     * @return
     * @throws IOException
     */
    public static synchronized File pictureWatermark(byte[] imgBytes, String text) throws IOException {
        ImageInputStream imageInputstream = new MemoryCacheImageInputStream(new ByteArrayInputStream(imgBytes));

        //根据图片文件获取读取器
        Iterator<ImageReader> it = ImageIO.getImageReaders(imageInputstream);
        //检测读取器是否存在
        ImageReader imageReader = it.next();
        //设置读取器输入流
        imageReader.setInput(imageInputstream);
        //从读取器取BufferedImage，这里只有一个，所以可以直接写0
        BufferedImage bufferedImage = imageReader.read(0);
        //开始加水印
        {
            //取画笔
            Graphics2D graphics2d = bufferedImage.createGraphics();
            //设置画笔文字抗锯齿
            graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            //将画笔移动到图片中央
            graphics2d.transform(AffineTransform.getTranslateInstance(bufferedImage.getWidth() / widthRatio, bufferedImage.getHeight() / heightRatio));
            //将画笔旋转一定弧度
            graphics2d.transform(AffineTransform.getRotateInstance(Math.toRadians(angle)));
            //计算图片外切圆半径
            float radius = Double.valueOf(Math.sqrt(bufferedImage.getWidth() * bufferedImage.getWidth() + bufferedImage.getHeight() * bufferedImage.getHeight()) / 2).floatValue();
            //设置画笔要用的字体，这里可以设置字体样式和大小
            Font waterMarkerFont = new Font(font, Font.PLAIN, size);
            //设置画笔字体
            graphics2d.setFont(waterMarkerFont);
            //设置画笔颜色
            graphics2d.setColor(Color.WHITE);
            //设置画笔操作透明度
            graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, transparency));
            //取画笔字体信息
            FontMetrics fontMetrics = graphics2d.getFontMetrics();
            //水印文字
            String waterMarker = text;
            //计算水印文字宽度，很多人卡在了这一步
            int stringWidth = fontMetrics.stringWidth(waterMarker);
            //循环添加水印，这里可以设置水印水平距离，单位：px
            for (float i = -radius; i <= radius; i += (stringWidth + bufferedImage.getHeight() / levelDistance)) {
                //这里可以设置水印垂直距离，单位：px
                for (float j = -radius; j <= radius; j += (fontMetrics.getHeight() + bufferedImage.getHeight() / verticalDistance)) {
                    //画水印
                    graphics2d.drawString(waterMarker, i, j);
                }
            }
            //释放画笔资源
            graphics2d.dispose();
        }
        //根据图片文件读取器获取图片文件写入器
        ImageWriter imageWriter = ImageIO.getImageWriter(imageReader);
        File file = new File(UUID.randomUUID() + suffix);
        //生成目标图片文件路径
        FileImageOutputStream fileOutputStream = new FileImageOutputStream(file);
        //设置写入器输出流
        imageWriter.setOutput(fileOutputStream);


        IIOImage iioImage = new IIOImage(bufferedImage, null, null);
        ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
        //jpg格式图片可设置输出图片文件的质量
        if (imageReader.getFormatName().equals("JPEG")) {
            //这一行固定这样写，跟下一行搭配
            imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            //跟上一行搭配，设置输出图片文件的质量
            imageWriteParam.setCompressionQuality(0.947F);
        }
        //写文件
        imageWriter.write(null, iioImage, imageWriteParam);
        //关闭写入器
        imageWriter.dispose();
        //关闭读取器
        imageReader.dispose();

        imageInputstream.close();

        if(file == null){
            return null;
        }
        return file;
    }
}
